/*
*********************************************************************************************************
*                                             bootload
*                                           MAIN函数文件
*
* 文件名称 : 0.mian.c
* 文件版本 : V0.01
* 文件描述 : main()函数入口，系统任务调度
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2015.12.28
*********************************************************************************************************
*/
#define __USART__5
/*
*********************************************************************************************************
*                                           头文件描述
*********************************************************************************************************
*/
#include <stdint.h>
#include "stm32f4xx.h"
#include "includes_boot.h"
#include "update_struct.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_rcc.h"
#include "flash.h"
#include "ctrl_io.h"
#include "wdg.h"

//#define  __attribute__ ((section (".ccmram")))

//收发数组
static uint8_t flg[2048] __attribute__ ((section (".ccmram")))  = {0};
static uint8_t xlg[20]   __attribute__ ((section (".ccmram")))  = {4};

static uint8_t runStatus =  0;     //命令执行结果
static uint8_t tmp       =  0;     //串口接收的临时数据
static uint8_t rec       =  0;     //数据头计数器
static uint8_t colon     =  0;     //":"标记
static uint16_t si       =  0;     //数据位置
static uint16_t rl       =  0;     //应收数据长度
static uint8_t d_nbr     =  0;     //执行成功的数据编号
static uint8_t f_up      =  0;     //收到06信号后,标记置1,控制相关LED可主循环
static uint32_t loop     = 30;     //主循环控制
static uint32_t baseAddr =  0;     //基地址


/*
*********************************************************************************************************
*                                            静态函数
*********************************************************************************************************
*/
//LED控制器
#define _bl_led_toggle(x) LED_Toggle(x)

//静态函数申明
static void bl_msgSend(uint8_t fg);
//模值和校验
static uint8_t CheckSum(uint8_t crcData[], uint16_t count)
{
  uint16_t sum = 0;
  for (uint16_t i = 0; i < count; i++) {
    sum += crcData[i];
  }
  return (uint8_t) (sum & 0xFF);
}
//初始化ISP串口
void isp_usart_init(void)
{
#ifdef __USART__1
#endif
#ifdef __USART__2
#endif
#ifdef __USART__3
#endif
#ifdef __USART__4
#endif
#ifdef __USART__5
  //配置串口5 38400 8 0 0 1 无中断
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  USART_ClockInitTypeDef USART_ClockInitStruct;

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);

  GPIO_PinAFConfig(GPIOC,GPIO_PinSource12, GPIO_AF_UART5);
  GPIO_PinAFConfig(GPIOD,GPIO_PinSource2,GPIO_AF_UART5);

  //TX PC12
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOC,&GPIO_InitStructure);

  //RX PD2
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOD,&GPIO_InitStructure);

  USART_DeInit(UART5);
  USART_StructInit(&USART_InitStructure);
  USART_InitStructure.USART_BaudRate = 38400;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(UART5, &USART_InitStructure);

  USART_ClockStructInit(&USART_ClockInitStruct);
  USART_ClockInit(UART5, &USART_ClockInitStruct);
  USART_Cmd(UART5, ENABLE);
#endif

#ifdef __USART__6
#endif
}
//发送数据
static void sendDate(uint8_t d)
{
#ifdef __USART__1
#endif
#ifdef __USART__2
#endif
#ifdef __USART__3
#endif
#ifdef __USART__4
#endif
#ifdef __USART__5
  USART_SendData(UART5, d);
  while(USART_GetFlagStatus(UART5, USART_FLAG_TC) == RESET);
#endif
#ifdef __USART__6
#endif
}
//检查并接收串口数据
static uint16_t receiveData(uint32_t i)
{
#ifdef __USART__1
  while(i--) {
    if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(USART1));
  }
  return(0xff);
#endif
#ifdef __USART__2
  while(i--) {
    if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(USART2));
  }
  return(0xff);
#endif
#ifdef __USART__3
  while(i--) {
    if(USART_GetFlagStatus(USART3,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(USART3));
  }
  return(0xff);
#endif
#ifdef __USART__4
  while(i--) {
    if(USART_GetFlagStatus(UART4,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(UART4));
  }
  return(0xff);
#endif
#ifdef __USART__5
  while(i--) {
    if(USART_GetFlagStatus(UART5,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(UART5));
  }
  return(0xff);
#endif
#ifdef __USART__6
  while(i--) {
    if(USART_GetFlagStatus(USART6,USART_FLAG_RXNE) == SET)
      return(USART_ReceiveData(USART6));
  }
  return(0xff);
#endif
}

//擦除app
static bool eraseApp(uint8_t s)
{
  uint32_t sector[11]={
    STM32F407_FLASH_ADDT_SECTOR_1_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_2_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_3_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_4_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_5_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_6_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_7_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_8_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_9_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_10_HEAD,
    STM32F407_FLASH_ADDT_SECTOR_11_HEAD,
  };
  uint32_t  j =  0;
  uint32_t  r =  0;
  if(s>11) {
    s = 11;
  }

  for(uint32_t i=0; i<s; i++) {
    LED_Toggle(WAR);
    r = eraseFlashSector(sector[i]+8);
    if(1 == r) {
      j += r;
      bl_msgSend(ORDER_REPE);
    } else {
      break;
    }
  }
  for(;;) {
    if(0xff == receiveData(LOOP_10_MS)) {
      if(0xff == receiveData(LOOP_10_MS)) {
        if(0xff == receiveData(LOOP_10_MS)) {
          break;
        }
      }
    }
  }
  return((s==j)?(true):(false));
}

//按照下发的数据分别执行相关任务
static uint8_t bl_func(void)
{
  uint32_t  fa;
  uint32_t* pd;
  uint32_t  ln;

  uint8_t r = ORDER_FALSE;

  switch (flg[D_FUNC]) {
    //写数据到存储
  case 0:
    //计算数据地址长度
    fa = ((uint32_t )(baseAddr + (flg[D_OFFSET_H]<<8) + flg[D_OFFSET_L]));
    pd = ((uint32_t*)(&(flg[D_DATA])));
    ln = ((uint32_t )((flg[D_LEN_H]<<8) + flg[D_LEN_L]))>>2;
    //检查数据的写入地址是否在允许范围内,保护bootloader区域不被错误数据破坏
    if(!(fa>=APP_ADDR_HEAD)&&((fa+(ln<<2))<=APP_ADDR_END)) {
      r = ORDER_OFFSETERR;
      break;
    }
    //写入数据
    if(ln == writeFlashWord(fa, pd, ln)) {
      //写入校验
      uint32_t* s;
      s = (uint32_t*)fa;
      for(uint32_t jy=0; jy<ln; jy++) {
        if(*s != *pd ) {
          r = ORDER_FALSE;
          break;
        }
        s  += 1; pd += 1;
      }
      r = ORDER_SUCCESS;
    } else {
      r = ORDER_FALSE;
    }
    f_up = BL_SWITCH_DATA;
    break;

    //文件结束
  case 1:
    f_up = BL_WAIT_RST;
    r = ORDER_SUCCESS;
    break;

    //计算扩展段基地址
  case 2:
    baseAddr = (flg[D_DATA]<<24) + (flg[D_DATA+1]<<16);
    r = ORDER_SUCCESS;
    break;

    //记录扩展段开始地址
  case 3:
    r = ORDER_SUCCESS;
    break;

    //计算线性段基地址
  case 4:
    baseAddr = (flg[D_DATA]<<24) + (flg[D_DATA+1]<<16);
    r = ORDER_SUCCESS;
    break;

    //记录线性段开始地址
  case 5:
    r = ORDER_SUCCESS;
    break;

    //上位机升级命令
  case 6:
    f_up = BL_WAIT_ORDER;
    r = ORDER_SUCCESS;
    break;

    //上位机重启命令
  case 7:
    f_up = BL_WAIT_RST;
    iwdgSet(2, 0xfff);
    r = ORDER_SUCCESS;
    break;

    //擦除app数据区域
  case 8:
    f_up = BL_ERASE_APP;
    if(true == eraseApp((flg[D_OFFSET_H]<<8)+flg[D_OFFSET_L]))
      {
        r = ORDER_SUCCESS;
      }
    break;

  default:
    break;

  }
  return(r);
}

//通讯回复 fg=0传输失败信息 1 成功信息
static void bl_msgSend(uint8_t fg)
{
  flg[BL_HEAD] = 0x5a;   //数据头
  flg[BL_LEN]  = 0x02;   //信息长度
  flg[BL_DNBR] = d_nbr;
  flg[BL_MSG]  = fg;
  flg[BL_SUM]  = CheckSum(&flg[0], 4);

  //发送之前监控3ms确认当前串口数据空闲
  for(;;) {
    if(0xff == receiveData(LOOP_1_MS)) {
      if(0xff == receiveData(LOOP_1_MS)) {
        if(0xff == receiveData(LOOP_1_MS)) {
          break;
        }
      }
    }
  }
  //发送数据
  for(uint8_t i=0; i<5; i++) {
    sendDate(flg[i]);
  }
  //清除必要的数据
  tmp     =  0;
  rec     =  0;
  colon   =  0;
  si      =  0;
  rl      =  0;
}
/*
*********************************************************************************************************
*
*                                           jumpToApp
*
* 函数名称 : jumpToApp()
* 函数版本 : V0.01
* 功能描述 : 跳转到APP
*          :
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2015.12.28
*********************************************************************************************************
*/
void jumpToApp(uint32_t appAddr)
{
  pFunc toAppAddr = (pFunc)(*(__IO uint32_t*) (appAddr + 4));
  __set_MSP(*(__IO uint32_t*) appAddr);
  toAppAddr();
}
/*
*********************************************************************************************************
*
*                                           MAIN函数
*
* 函数名称 : main()
* 函数版本 : V0.01
* 功能描述 : main()函数
*          :
* 编写人员 : HHL
* 修改人员 :
* 编修描述 : V0.01，时间2015.12.28
*********************************************************************************************************
*/
int main (void)
{
  //LED初始化
  led_io_init();
  led_off(LEDALL);
  //串口初始化
  isp_usart_init();

  while(loop) {

    for (int i = 0; i < 2048; i++) {
        flg[i] += 1;
    }
    for (int i = 0; i < 20; i++) {
        xlg[i] += 1;
    }

    if (tmp == receiveData(LOOP_100_MS)) {
      //连续的0x5a
      if(0x5a == tmp) {
        rec++;
      } else {
        if(rec>0) {
          rec--;
        }
      }
      //间隔符 ":"
      if (0x3a == tmp) {
        colon++;
      }
      //判断真实数据到达
      if((rec>3)&&(colon>0)) {
        //数据编号
        flg[D_NBR] = receiveData(LOOP_10_MS);
        //信息长度
        flg[D_LEN_H] = receiveData(LOOP_10_MS);
        flg[D_LEN_L] = receiveData(LOOP_10_MS);
        //数据长度
        rl = (7 + (flg[D_LEN_H]<<8) + flg[D_LEN_L]) ;
        //接收数据
        for(si=3; si<rl; si++) {
          flg[si] = receiveData(LOOP_10_MS);
        }
        //和校验
        if(flg[rl-1] == CheckSum((uint8_t*)(&(flg[0])), (rl-1))) {
          //检查d_nbr是否重复,命令不重复执行
          if (d_nbr != flg[D_NBR]) {
            //数据或任务处理
            runStatus = bl_func();
            //执行成功,记录当前的数据编号
            if(ORDER_SUCCESS == runStatus) {
              d_nbr = flg[D_NBR];
            }
            //回应上位机信号
            bl_msgSend(runStatus);
          } else {
            //命令重复回复命令成功,取下一条
            bl_msgSend(ORDER_REPE);
          }
        } else {
          //数据校验,失败
          bl_msgSend(ORDER_CHECKERR);
        }
      }
    }

    //信号和循环控制标记
    switch(f_up) {

      //等待数据信号        LED:   RUN
    case BL_WAIT_MSG:
      LED_Toggle(RUN1);
      LED_Toggle(RUN2);
      break;

      //收到请求,等待命令   LED:   RUN + ABN
    case BL_WAIT_ORDER:
      LED_Toggle(RUN1);
      LED_Toggle(RUN2);
      LED_Toggle(ABN);
      loop = 0xffff;
      break;

      //擦除APP数据         LED:   RUN + ABN + WAR
    case BL_ERASE_APP:
      LED_Toggle(RUN1);
      LED_Toggle(RUN2);
      LED_Toggle(ABN);
      LED_Toggle(WAR);
      loop = 0xffff;
      break;

      //交互数据           LED:   RUN + ABN + WAR + ERR
    case BL_SWITCH_DATA:
      LED_Toggle(RUN1);
      LED_Toggle(RUN2);
      LED_Toggle(ABN);
      LED_Toggle(WAR);
      LED_Toggle(ERR);
      loop = 0xffff;
      break;

      //升级完成等待重启   LED:   RUN + ABN + WAR + ERR + STA1 + STA2
    case BL_WAIT_RST:
      LED_Toggle(RUN1);
      LED_Toggle(RUN2);
      LED_Toggle(ABN);
      LED_Toggle(WAR);
      LED_Toggle(ERR);
      LED_Toggle(STA1);
      LED_Toggle(STA2);
      loop = 0xffff;
      break;
    }
  }
  //转到用户程序
  jumpToApp(APPADDR);

  return (0);
}
